namespace YXShop.ExcelLite
{
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Globalization;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;

    [LicenseProvider(typeof(GemBoxLicenseProvider))]
    public sealed class ExcelFile
    {
        private CellStyleCachedCollection cellStyleCache;
        private byte[] documentSummaryStream;
        private int groupMethodsAffectedCellsLimit;
        internal int HashFactorA;
        internal int HashFactorB;
        internal string IDText;
        private License license;
        public const int MaxCellStyles = 0xf8b;
        public const int MaxColors = 0x38;
        public const int MaxColumns = 0x100;
        public const int MaxRows = 0x10000;
        internal PreservedRecords PreservedGlobalRecords;
        private bool protectedMbr;
        private YXShop.ExcelLite.RowColumnResolutionMethod rowColumnResolutionMethod;
        private byte[] summaryStream;
        private ExcelWorksheetCollection worksheets;

        public event LimitEventHandler LimitNear;

        public event LimitEventHandler LimitReached;

        public ExcelFile()
        {
            this.rowColumnResolutionMethod = YXShop.ExcelLite.RowColumnResolutionMethod.RowOverColumn;
            this.groupMethodsAffectedCellsLimit = 0x2710;
            this.HashFactorA = 0x65;
            this.HashFactorB = 0x33;
            this.IDText = "YXShop.ExcelLite Free 2.3 for .NET 1.1, Version=23.1.5000.1000";
            this.Initialize();
        }

        [Obsolete("This constructor is obsolete. Use default constructor and LoadXls() method instead."), EditorBrowsable(EditorBrowsableState.Never)]
        public ExcelFile(string fileName)
        {
            this.rowColumnResolutionMethod = YXShop.ExcelLite.RowColumnResolutionMethod.RowOverColumn;
            this.groupMethodsAffectedCellsLimit = 0x2710;
            this.HashFactorA = 0x65;
            this.HashFactorB = 0x33;
            this.IDText = "YXShop.ExcelLite Free 2.3 for .NET 1.1, Version=23.1.5000.1000";
            this.Initialize();
            this.LoadXls(fileName, XlsOptions.PreserveAll);
        }

        [Obsolete("This constructor is obsolete. Use default constructor and LoadCsv() method instead."), EditorBrowsable(EditorBrowsableState.Never)]
        public ExcelFile(string fileName, CsvType csvType)
        {
            this.rowColumnResolutionMethod = YXShop.ExcelLite.RowColumnResolutionMethod.RowOverColumn;
            this.groupMethodsAffectedCellsLimit = 0x2710;
            this.HashFactorA = 0x65;
            this.HashFactorB = 0x33;
            this.IDText = "YXShop.ExcelLite Free 2.3 for .NET 1.1, Version=23.1.5000.1000";
            this.Initialize();
            this.LoadCsv(fileName, csvType);
        }

        [Obsolete("This constructor is obsolete. Use default constructor and LoadXls() method instead."), EditorBrowsable(EditorBrowsableState.Never)]
        public ExcelFile(string fileName, XlsOptions xlsOptions)
        {
            this.rowColumnResolutionMethod = YXShop.ExcelLite.RowColumnResolutionMethod.RowOverColumn;
            this.groupMethodsAffectedCellsLimit = 0x2710;
            this.HashFactorA = 0x65;
            this.HashFactorB = 0x33;
            this.IDText = "YXShop.ExcelLite Free 2.3 for .NET 1.1, Version=23.1.5000.1000";
            this.Initialize();
            this.LoadXls(fileName, xlsOptions);
        }

        internal void CopyDrawings(ExcelFile source)
        {
            PreservedRecords preservedGlobalRecords = source.PreservedGlobalRecords;
            if (preservedGlobalRecords != null)
            {
                if (this.PreservedGlobalRecords == null)
                {
                    this.PreservedGlobalRecords = new PreservedRecords();
                }
                this.PreservedGlobalRecords.CopyRecords(preservedGlobalRecords, "MSODRAWINGGROUP");
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public static void DumpToLowLevelXml(string sourceFileName, string destinationFileName)
        {
            byte[] ss = null;
            SaveLowLevelXML(ReadHelper(sourceFileName, false, ref ss, ref ss), destinationFileName, sourceFileName);
        }

        internal void ExceptionIfOverAffectedCellsLimit(int cellCount)
        {
            int groupMethodsAffectedCellsLimit = this.groupMethodsAffectedCellsLimit;
            if (cellCount > groupMethodsAffectedCellsLimit)
            {
                throw new InvalidOperationException(string.Concat(new object[] { "You are trying to modify ", cellCount, " cells while ExcelFile.GroupMethodsAffectedCellsLimit is set to ", groupMethodsAffectedCellsLimit, ". If you want to perform this operation, you need to change ExcelFile.GroupMethodsAffectedCellsLimit accordingly." }));
            }
        }

        private void Initialize()
        {
            this.license = LicenseManager.Validate(typeof(ExcelFile), this);
            if (this.license.LicenseKey != "Valid")
            {
                throw new LicenseException(typeof(ExcelFile), this, "Invalid license.");
            }
            this.worksheets = new ExcelWorksheetCollection(this);
            this.cellStyleCache = new CellStyleCachedCollection(QueueSizeFromAffectedCellsLimit(this.groupMethodsAffectedCellsLimit));
        }

        public void LoadCsv(string fileName, char separator)
        {
            this.Reset();
            using (StreamReader reader = new StreamReader(fileName))
            {
                string[] strArray;
                string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
                ExcelWorksheet worksheet = this.worksheets.Add(fileNameWithoutExtension);
                int maxRowCount = 0;
                while (ReadSplitCsvLine(reader, separator, out strArray))
                {
                    if (maxRowCount < (this.HashFactorA - this.HashFactorB))
                    {
                        for (int i = 0; i < strArray.Length; i++)
                        {
                            if (strArray[i].Length > 0)
                            {
                                worksheet.Cells[maxRowCount, i].Value = ParseCSValue(strArray[i]);
                            }
                        }
                    }
                    maxRowCount++;
                }
                if (maxRowCount > (this.HashFactorA - this.HashFactorB))
                {
                    this.OnLimitReached(fileName, LimitEventOperation.CsvReading, maxRowCount, 1, false);
                }
                else if (maxRowCount > (((this.HashFactorA - this.HashFactorB) * 4) / 5))
                {
                    this.OnLimitNear(fileName, LimitEventOperation.CsvReading, maxRowCount, 1, false);
                }
            }
        }

        public void LoadCsv(string fileName, CsvType csvType)
        {
            switch (csvType)
            {
                case CsvType.CommaDelimited:
                    this.LoadCsv(fileName, ',');
                    break;

                case CsvType.SemicolonDelimited:
                    this.LoadCsv(fileName, ';');
                    break;

                case CsvType.TabDelimited:
                    this.LoadCsv(fileName, '\t');
                    break;

                default:
                    throw new Exception("Internal: Unknown CsvType.");
            }
        }

        public void LoadXls(string fileName)
        {
            this.LoadXls(fileName, XlsOptions.PreserveAll);
        }

        public void LoadXls(string fileName, XlsOptions xlsOptions)
        {
            this.Reset();
            AbsXLSRecords records = ReadHelper(fileName, (xlsOptions & XlsOptions.PreserveSummaries) != XlsOptions.None, ref this.summaryStream, ref this.documentSummaryStream);
            new XLSFileReader(this, xlsOptions).ImportRecords(records, fileName);
        }

        internal LimitEventArgs OnLimitNear(string fileName, LimitEventOperation operation, int maxRowCount, int worksheetCount, bool writeWarningWorksheet)
        {
            LimitEventArgs e = new LimitEventArgs(fileName, operation, maxRowCount, worksheetCount, writeWarningWorksheet);
            if (this.LimitNear != null)
            {
                this.LimitNear(this, e);
            }
            return e;
        }

        internal LimitEventArgs OnLimitReached(string fileName, LimitEventOperation operation, int maxRowCount, int worksheetCount, bool writeWarningWorksheet)
        {
            LimitEventArgs e = new LimitEventArgs(fileName, operation, maxRowCount, worksheetCount, writeWarningWorksheet);
            if (this.LimitReached != null)
            {
                this.LimitReached(this, e);
            }
            return e;
        }

        private static object ParseCSValue(string item)
        {
            double num;
            NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands;
            if (double.TryParse(item, style, CultureInfo.CurrentCulture, out num))
            {
                return num;
            }
            return item;
        }

        private static int QueueSizeFromAffectedCellsLimit(int affectedCellsLimit)
        {
            return Math.Min(2 * affectedCellsLimit, 0x7a120);
        }

        private static AbsXLSRecords ReadHelper(string fileName, bool readSummaryStreams, ref byte[] ss, ref byte[] dss)
        {
            StructuredStorageFileBase base2 = StructuredStorageFileBase.Open(fileName);
            MemoryStream input = new MemoryStream(base2.ReadStream("Workbook"));
            if (readSummaryStreams)
            {
                try
                {
                    ss = base2.ReadStream('\x0005' + "SummaryInformation");
                }
                catch
                {
                }
                try
                {
                    dss = base2.ReadStream('\x0005' + "DocumentSummaryInformation");
                }
                catch
                {
                }
            }
            base2.Close();
            BinaryReader br = new BinaryReader(input, new UnicodeEncoding());
            AbsXLSRecords records = new AbsXLSRecords();
            records.Read(br);
            br.Close();
            input.Close();
            return records;
        }

        private static bool ReadSplitCsvLine(StreamReader sr, char separator, out string[] values)
        {
            ArrayList list = new ArrayList();
            StringBuilder builder = new StringBuilder();
            bool flag = true;
            char ch = separator;
            bool flag2 = true;
            string str = null;
            do
            {
                string str2 = sr.ReadLine();
                if (str2 == null)
                {
                    flag2 = false;
                    break;
                }
                str2 = str + str2;
                for (int i = 0; i < str2.Length; i++)
                {
                    char ch2 = str2[i];
                    if (flag)
                    {
                        if (ch2 == separator)
                        {
                            list.Add(builder.ToString());
                            builder = new StringBuilder();
                            ch = ch2;
                        }
                        else if ((ch2 == '"') && (ch == separator))
                        {
                            flag = false;
                            ch = ch2;
                        }
                        else
                        {
                            builder.Append(ch2);
                            if (!char.IsWhiteSpace(ch2))
                            {
                                ch = ch2;
                            }
                        }
                    }
                    else if (ch2 == '"')
                    {
                        if (((i + 1) < str2.Length) && (str2[i + 1] == '"'))
                        {
                            builder.Append('"');
                            i++;
                        }
                        else
                        {
                            flag = true;
                        }
                    }
                    else
                    {
                        builder.Append(ch2);
                    }
                }
                str = "\n";
            }
            while (!flag);
            list.Add(builder.ToString());
            values = (string[]) list.ToArray(typeof(string));
            return flag2;
        }

        private void Reset()
        {
            this.worksheets = new ExcelWorksheetCollection(this);
            this.cellStyleCache = new CellStyleCachedCollection(QueueSizeFromAffectedCellsLimit(this.groupMethodsAffectedCellsLimit));
            this.protectedMbr = false;
            this.summaryStream = null;
            this.documentSummaryStream = null;
            this.PreservedGlobalRecords = null;
        }

        public void SaveCsv(string fileName, char separator)
        {
            char[] anyOf = new char[] { separator, '"', '\n' };
            using (StreamWriter writer = new StreamWriter(fileName))
            {
                ExcelWorksheet activeWorksheet = this.Worksheets.ActiveWorksheet;
                int num = -1;
                int num2 = -1;
                int maxRowCount = 0;
                for (int i = 0; i < 2; i++)
                {
                    if (i == 0)
                    {
                        maxRowCount = activeWorksheet.Rows.Count;
                    }
                    else
                    {
                        maxRowCount = num + 1;
                    }
                    for (int j = 0; j < maxRowCount; j++)
                    {
                        int count;
                        if (i == 0)
                        {
                            count = activeWorksheet.Rows[j].AllocatedCells.Count;
                        }
                        else
                        {
                            count = num2 + 1;
                            if (j >= (this.HashFactorA - this.HashFactorB))
                            {
                                continue;
                            }
                        }
                        for (int k = 0; k < count; k++)
                        {
                            ExcelCell cell = activeWorksheet.Cells[j, k];
                            object obj2 = cell.Value;
                            if ((obj2 != null) && !(obj2 is DBNull))
                            {
                                CellRange mergedRange = cell.MergedRange;
                                if ((mergedRange == null) || ((mergedRange.FirstRowIndex == j) && (mergedRange.FirstColumnIndex == k)))
                                {
                                    if (i == 0)
                                    {
                                        if (k > num2)
                                        {
                                            num2 = k;
                                        }
                                    }
                                    else
                                    {
                                        string str = obj2.ToString();
                                        if (str.IndexOfAny(anyOf) != -1)
                                        {
                                            StringBuilder builder = new StringBuilder(str);
                                            builder.Replace("\"", "\"\"");
                                            str = '"' + builder.ToString() + '"';
                                        }
                                        writer.Write(str);
                                    }
                                }
                            }
                            if ((i == 1) && ((k + 1) < count))
                            {
                                writer.Write(separator);
                            }
                        }
                        if (i == 0)
                        {
                            if (j > num)
                            {
                                num = j;
                            }
                        }
                        else
                        {
                            writer.WriteLine();
                        }
                    }
                }
                if (maxRowCount > (this.HashFactorA - this.HashFactorB))
                {
                    this.OnLimitReached(fileName, LimitEventOperation.CsvWriting, maxRowCount, 1, false);
                }
                else if (maxRowCount > (((this.HashFactorA - this.HashFactorB) * 4) / 5))
                {
                    this.OnLimitNear(fileName, LimitEventOperation.CsvWriting, maxRowCount, 1, false);
                }
            }
        }

        public void SaveCsv(string fileName, CsvType csvType)
        {
            switch (csvType)
            {
                case CsvType.CommaDelimited:
                    this.SaveCsv(fileName, ',');
                    break;

                case CsvType.SemicolonDelimited:
                    this.SaveCsv(fileName, ';');
                    break;

                case CsvType.TabDelimited:
                    this.SaveCsv(fileName, '\t');
                    break;

                default:
                    throw new Exception("Internal: Unknown CsvType.");
            }
        }

        private static void SaveLowLevelXML(AbsXLSRecords records, string fileName, string sourceFileName)
        {
            StreamWriter writer = new StreamWriter(fileName);
            if (sourceFileName != null)
            {
                writer.WriteLine("<!-- FileName: {0} -->", sourceFileName);
            }
            writer.WriteLine("<ExcelFile>");
            string name = null;
            int index = 0;
            foreach (AbsXLSRec rec in records)
            {
                if (rec.Name == name)
                {
                    index++;
                }
                else
                {
                    index = 0;
                    name = rec.Name;
                }
                writer.WriteLine(rec.GetXMLRecord(index));
            }
            writer.Write("</ExcelFile>");
            writer.Close();
        }

        public void SaveXls(string fileName)
        {
            SaveXLSInternal(new XLSFileWriter(this, fileName).GetRecords(), fileName, this.summaryStream, this.documentSummaryStream);
        }

        private static void SaveXLSInternal(AbsXLSRecords records, string fileName, byte[] ss, byte[] dss)
        {
            StructuredStorageFileBase base2 = StructuredStorageFileBase.Create(fileName);
            base2.WriteStream("Workbook", XLSFileWriter.GetStream(records));
            if (ss != null)
            {
                base2.WriteStream('\x0005' + "SummaryInformation", ss);
            }
            if (dss != null)
            {
                base2.WriteStream('\x0005' + "DocumentSummaryInformation", dss);
            }
            base2.Close();
        }

        public static bool SupportsType(Type type)
        {
            if (type.IsEnum)
            {
                return true;
            }
            switch (type.FullName)
            {
                case "System.DBNull":
                case "System.Byte":
                case "System.SByte":
                case "System.Int16":
                case "System.UInt16":
                case "System.Int64":
                case "System.UInt64":
                case "System.UInt32":
                case "System.Int32":
                case "System.Single":
                case "System.Double":
                case "System.Boolean":
                case "System.Char":
                case "System.Text.StringBuilder":
                case "System.Decimal":
                case "System.DateTime":
                case "System.String":
                    return true;
            }
            return false;
        }

        internal static void ThrowExceptionForUnsupportedType(Type type)
        {
            if (!SupportsType(type))
            {
                throw new NotSupportedException("Type " + type.Name + " is not supported.");
            }
        }

        internal CellStyleCachedCollection CellStyleCache
        {
            get
            {
                return this.cellStyleCache;
            }
        }

        public int GroupMethodsAffectedCellsLimit
        {
            get
            {
                return this.groupMethodsAffectedCellsLimit;
            }
            set
            {
                if (value < 5)
                {
                    throw new ArgumentOutOfRangeException("value", value, "GroupMethodsAffectedCellsLimit must be larger than 5.");
                }
                this.groupMethodsAffectedCellsLimit = value;
                this.cellStyleCache.AddQueueSize = QueueSizeFromAffectedCellsLimit(value);
            }
        }

        public bool Protected
        {
            get
            {
                return this.protectedMbr;
            }
            set
            {
                this.protectedMbr = value;
            }
        }

        public YXShop.ExcelLite.RowColumnResolutionMethod RowColumnResolutionMethod
        {
            get
            {
                return this.rowColumnResolutionMethod;
            }
            set
            {
                this.rowColumnResolutionMethod = value;
            }
        }

        public ExcelWorksheetCollection Worksheets
        {
            get
            {
                return this.worksheets;
            }
        }
    }
}

